package org.zjx.manager;

import org.zjx.command.ICommand;
import org.zjx.core.GameWindow;
import org.zjx.core.WindowSession;
import org.zjx.util.WindowLayoutHelper;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 基于纯Command体系的窗口池管理器（整改后版本）
 */
public class WindowPool {
    private static WindowPool instance;

    // 等待队列：等待执行的窗口命令
    private final PriorityBlockingQueue<CommandWaitingWindow> waitingWindows;

    // 活跃会话：当前正在执行的窗口会话
    private final ConcurrentMap<String, WindowSession> activeSessions;

    // 可用屏幕位置：虚拟屏幕坐标
    private final BlockingQueue<Rectangle> availableScreenPositions;

    // 线程池执行窗口任务
    private final ExecutorService taskExecutor;

    // 控制变量
    private volatile boolean running = false;
    private Thread schedulerThread;
    private Thread sessionMonitorThread;

    // 同步锁
    private final ReentrantLock poolLock = new ReentrantLock();
    private final Condition resourcesAvailable = poolLock.newCondition();

    // 统计信息
    private final AtomicInteger totalSubmitted = new AtomicInteger(0);
    private final AtomicInteger totalCompleted = new AtomicInteger(0);
    private final AtomicInteger totalFailures = new AtomicInteger(0);

    // 配置参数
    private static final int SCHEDULING_INTERVAL_MS = 50;
    private static final int SESSION_MONITOR_INTERVAL_MS = 1000;
    private static final long SESSION_TIMEOUT_MS = 30000;
    private static final int MAX_SCREEN_POSITIONS = 10;
    private static final int DEFAULT_WINDOW_WIDTH = 800;
    private static final int DEFAULT_WINDOW_HEIGHT = 600;

    private WindowPool() {
        this.waitingWindows = new PriorityBlockingQueue<>(11,
                Comparator.comparingLong(CommandWaitingWindow::getSubmitTime));
        this.activeSessions = new ConcurrentHashMap<>();
        this.availableScreenPositions = new LinkedBlockingQueue<>();
        this.taskExecutor = Executors.newCachedThreadPool(r -> {
            Thread t = new Thread(r, "WindowTask-" + System.nanoTime());
            t.setDaemon(true);
            return t;
        });

        initializeScreenPositions();
    }

    public static synchronized WindowPool getInstance() {
        if (instance == null) {
            instance = new WindowPool();
        }
        return instance;
    }

    /**
     * 初始化可用的屏幕位置
     */
    private void initializeScreenPositions() {
        try {
            int maxPosition = WindowLayoutHelper.calculateMaxWindows(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
            List<Rectangle> positions = WindowLayoutHelper.calculateWindowPositions(maxPosition, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);

            availableScreenPositions.addAll(positions);
            System.out.println("[WindowPool] Initialized " + positions.size() + " screen positions");
        } catch (Exception e) {
            System.err.println("[WindowPool] Failed to initialize screen positions: " + e.getMessage());
            createFallbackPositions();
        }
    }

    /**
     * 创建备用的屏幕位置
     */
    private void createFallbackPositions() {
        Dimension screenSize = WindowLayoutHelper.getScreenSize();
        int cols = (int) Math.sqrt(MAX_SCREEN_POSITIONS);
        int rows = (MAX_SCREEN_POSITIONS + cols - 1) / cols;

        int width = screenSize.width / (cols + 1);
        int height = screenSize.height / (rows + 1);

        for (int i = 0; i < MAX_SCREEN_POSITIONS; i++) {
            int row = i / cols;
            int col = i % cols;
            int x = col * width + 50;
            int y = row * height + 50;

            if (x + width <= screenSize.width && y + height <= screenSize.height) {
                availableScreenPositions.offer(new Rectangle(x, y, width, height));
            }
        }
    }

    /**
     * 启动窗口池
     */
    public void start() {
        if (running) {
            return;
        }

        running = true;

        // 启动调度线程
        schedulerThread = new Thread(this::schedulingLoop, "WindowPool-Scheduler");
        schedulerThread.setDaemon(true);
        schedulerThread.start();

        // 启动会话监控线程
        sessionMonitorThread = new Thread(this::enhancedSessionMonitoringLoop, "WindowPool-SessionMonitor");
        sessionMonitorThread.setDaemon(true);
        sessionMonitorThread.start();

        System.out.println("[WindowPool] Started successfully with enhanced session monitor");
    }

    /**
     * 调度循环
     */
    private void schedulingLoop() {
        System.out.println("[WindowPool] Scheduler started");

        while (running) {
            try {
                int assigned = tryAssignTasks();

                if (assigned == 0) {
                    poolLock.lock();
                    try {
                        if (waitingWindows.isEmpty() || availableScreenPositions.isEmpty()) {
                            resourcesAvailable.await(SCHEDULING_INTERVAL_MS, TimeUnit.MILLISECONDS);
                        }
                    } finally {
                        poolLock.unlock();
                    }
                }

            } catch (InterruptedException e) {
                if (running) {
                    System.out.println("[WindowPool] Scheduler interrupted");
                }
                break;
            } catch (Exception e) {
                System.err.println("[WindowPool] Error in scheduler: " + e.getMessage());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                    break;
                }
            }
        }

        System.out.println("[WindowPool] Scheduler stopped");
    }

    /**
     * 增强的会话监控循环
     */
    private void enhancedSessionMonitoringLoop() {
        System.out.println("[WindowPool] Enhanced session monitor started");

        while (running) {
            try {
                // 1. 正常清理空闲会话
                enhancedCleanupIdleSessions();

                // 2. 检查并处理僵尸会话
                cleanupZombieSessions();

                // 3. 打印会话状态统计
                logSessionStats();

                Thread.sleep(SESSION_MONITOR_INTERVAL_MS);
            } catch (InterruptedException e) {
                if (running) {
                    System.out.println("[WindowPool] Session monitor interrupted");
                }
                break;
            } catch (Exception e) {
                System.err.println("[WindowPool] Error in session monitor: " + e.getMessage());
            }
        }

        System.out.println("[WindowPool] Session monitor stopped");
    }

    /**
     * 清理僵尸会话（长时间无响应的ACTIVE会话）
     */
    private void cleanupZombieSessions() {
        long currentTime = System.currentTimeMillis();
        Iterator<Map.Entry<String, WindowSession>> it = activeSessions.entrySet().iterator();

        int zombieCount = 0;

        while (it.hasNext()) {
            Map.Entry<String, WindowSession> entry = it.next();
            WindowSession session = entry.getValue();
            String sessionId = entry.getKey();

            if (session.needForceClose(SESSION_TIMEOUT_MS)) {
                System.out.printf("[WindowPool] Detected zombie session: %s (inactive for %dms)%n",
                        sessionId, currentTime - session.getLastActivityTime());

                session.forceClose();
                it.remove();
                returnScreenPosition(session.getScreenWindow().getBounds());
                zombieCount++;

                totalFailures.incrementAndGet();
            }
        }

        if (zombieCount > 0) {
            System.out.printf("[WindowPool] Cleaned up %d zombie sessions%n", zombieCount);
        }
    }

    /**
     * 增强的空闲会话清理
     */
    private void enhancedCleanupIdleSessions() {
        Iterator<Map.Entry<String, WindowSession>> it = activeSessions.entrySet().iterator();
        int cleanedCount = 0;

        while (it.hasNext()) {
            Map.Entry<String, WindowSession> entry = it.next();
            WindowSession session = entry.getValue();
            String sessionId = entry.getKey();

            // 检查会话是否可以安全关闭（引用计数为0且空闲5秒）
            if (session.getReferenceCount() == 0 &&
                    (System.currentTimeMillis() - session.getLastActivityTime()) > 5000) {
                System.out.printf("[WindowPool] Cleaning up idle session: %s (inactive for %dms)%n",
                        sessionId, System.currentTimeMillis() - session.getLastActivityTime());
                session.unbindWindow();
                it.remove();
                returnScreenPosition(session.getScreenWindow().getBounds());
                cleanedCount++;
            }
        }

        if (cleanedCount > 0) {
            System.out.printf("[WindowPool] Cleaned up %d idle sessions%n", cleanedCount);
        }
    }

    /**
     * 记录会话状态统计
     */
    private void logSessionStats() {
        int activeCount = 0;
        int idleCount = 0;
        int totalRefCount = 0;

        for (WindowSession session : activeSessions.values()) {
            if (session.getState() == WindowSession.SessionState.ACTIVE) {
                activeCount++;
            } else if (session.getState() == WindowSession.SessionState.IDLE) {
                idleCount++;
            }
            totalRefCount += session.getReferenceCount();
        }

        System.out.printf("[WindowPool] Session Stats - Active: %d, Idle: %d, TotalRefs: %d%n",
                activeCount, idleCount, totalRefCount);
    }

    /**
     * 尝试分配任务
     */
    private int tryAssignTasks() {
        int assignedCount = 0;

        while (!waitingWindows.isEmpty() && !availableScreenPositions.isEmpty()) {
            CommandWaitingWindow waiting = waitingWindows.poll();
            Rectangle screenPos = availableScreenPositions.poll();

            if (waiting != null && screenPos != null) {
                assignTaskToExecutor(waiting, screenPos);
                assignedCount++;
            }
        }

        return assignedCount;
    }

    /**
     * 将任务分配给执行器
     */
    private void assignTaskToExecutor(CommandWaitingWindow waiting, Rectangle screenPos) {
        System.out.printf("[WindowPool] Assigning command %s for window %s to executor%n",
                waiting.command.getCommandName(), waiting.window.getId());

        taskExecutor.submit(() -> {
            String sessionId = "Session-" + System.currentTimeMillis() + "-" +
                    waiting.window.getId().hashCode();
            WindowSession session = null;

            try {
                session = new WindowSession(sessionId, screenPos);
                activeSessions.put(sessionId, session);

                System.out.printf("[WindowPool] Starting command %s for window %s at position %s%n",
                        waiting.command.getCommandName(), waiting.window.getId(), screenPos);

                if (session.bindWindow(waiting.window)) {
                    boolean submitted = session.submitCommand(waiting.command);

                    if (submitted) {
                        System.out.printf("[WindowPool] Command %s submitted successfully for window %s%n",
                                waiting.command.getCommandName(), waiting.window.getId());

                        session.setLastActivityTime(System.currentTimeMillis());
                        session.setCommandCount(1);

                    } else {
                        throw new RuntimeException("Failed to submit command to session");
                    }
                } else {
                    throw new RuntimeException("Failed to bind window to session");
                }

            } catch (Exception e) {
                totalFailures.incrementAndGet();
                System.err.printf("[WindowPool] Command %s failed for window %s: %s%n",
                        waiting.command.getCommandName(), waiting.window.getId(), e.getMessage());
                e.printStackTrace();

                if (session != null) {
                    cleanupSession(session, sessionId, screenPos);
                }
            }
        });
    }

    /**
     * 清理会话资源
     */
    private void cleanupSession(WindowSession session, String sessionId, Rectangle screenPos) {
        if (session != null) {
            session.unbindWindow();
            activeSessions.remove(sessionId);
        }

        returnScreenPosition(screenPos);
    }

    /**
     * 归还屏幕位置
     */
    private void returnScreenPosition(Rectangle screenPos) {
        if (screenPos != null) {
            availableScreenPositions.offer(screenPos);
            signalScheduler();
        }
    }

    /**
     * 通知调度器
     */
    private void signalScheduler() {
        poolLock.lock();
        try {
            resourcesAvailable.signalAll();
        } finally {
            poolLock.unlock();
        }
    }

    // ==================== 公共API方法 ====================

    /**
     * 提交Command任务
     */
    public void submitCommandTask(GameWindow window, ICommand command) {
        if (window == null || command == null) {
            throw new IllegalArgumentException("Window and command cannot be null");
        }

        if (!running) {
            throw new IllegalStateException("WindowPool is not running");
        }

        poolLock.lock();
        try {
            CommandWaitingWindow waiting = new CommandWaitingWindow(window, command);
            waitingWindows.offer(waiting);
            totalSubmitted.incrementAndGet();

            System.out.printf("[WindowPool] Submitted command %s for window %s (waiting: %d, available screens: %d)%n",
                    command.getCommandName(), window.getId(), waitingWindows.size(), availableScreenPositions.size());

            resourcesAvailable.signalAll();

        } finally {
            poolLock.unlock();
        }
    }

    /**
     * 批量提交Command任务
     */
    public void submitBatchCommands(Map<GameWindow, ICommand> commands) {
        if (commands == null || commands.isEmpty()) {
            throw new IllegalArgumentException("Commands map cannot be null or empty");
        }

        for (Map.Entry<GameWindow, ICommand> entry : commands.entrySet()) {
            submitCommandTask(entry.getKey(), entry.getValue());
        }

        System.out.println("[WindowPool] Submitted batch commands: " + commands.size() + " tasks");
    }

    /**
     * 移除窗口
     */
    public void removeWindow(GameWindow window) {
        poolLock.lock();
        try {
            // 从等待队列移除
            waitingWindows.removeIf(waiting -> waiting.window == window);

            // 从活跃会话移除
            activeSessions.values().removeIf(session ->
                    session.getGameWindow() == window);

            System.out.printf("[WindowPool] Removed window %s%n", window.getId());

        } finally {
            poolLock.unlock();
        }
    }

    /**
     * 强制清理指定窗口的所有会话
     */
    public void forceCleanupWindow(GameWindow window) {
        poolLock.lock();
        try {
            // 从等待队列移除
            waitingWindows.removeIf(waiting -> waiting.window == window);

            // 从活跃会话强制移除
            Iterator<Map.Entry<String, WindowSession>> it = activeSessions.entrySet().iterator();
            int cleanedCount = 0;

            while (it.hasNext()) {
                Map.Entry<String, WindowSession> entry = it.next();
                WindowSession session = entry.getValue();

                if (session.getGameWindow() == window) {
                    System.out.printf("[WindowPool] Force cleaning window %s from session %s%n",
                            window.getId(), entry.getKey());

                    session.forceClose();
                    it.remove();
                    returnScreenPosition(session.getScreenWindow().getBounds());
                    cleanedCount++;
                }
            }

            System.out.printf("[WindowPool] Force cleaned %d sessions for window %s%n",
                    cleanedCount, window.getId());

        } finally {
            poolLock.unlock();
        }
    }

    /**
     * 获取等待队列大小
     */
    public int getWaitingQueueSize() {
        return waitingWindows.size();
    }

    /**
     * 获取活跃会话数量
     */
    public int getActiveSessionsCount() {
        return activeSessions.size();
    }

    /**
     * 获取可用屏幕位置数量
     */
    public int getAvailableScreenPositionsCount() {
        return availableScreenPositions.size();
    }

    /**
     * 检查窗口是否在等待队列中
     */
    public boolean isWindowInQueue(GameWindow window) {
        return waitingWindows.stream()
                .anyMatch(waiting -> waiting.window == window);
    }

    /**
     * 检查窗口是否在活跃会话中
     */
    public boolean isWindowActive(GameWindow window) {
        return activeSessions.values().stream()
                .anyMatch(session -> session.getGameWindow() == window);
    }

    /**
     * 获取状态信息
     */
    public String getStatus() {
        return String.format(
                "WindowPool Status [Running: %s]\n" +
                        "Waiting Commands: %d\n" +
                        "Active Sessions: %d\n" +
                        "Available Screens: %d\n" +
                        "Submitted: %d, Completed: %d, Failures: %d",
                running,
                waitingWindows.size(),
                activeSessions.size(),
                availableScreenPositions.size(),
                totalSubmitted.get(),
                totalCompleted.get(),
                totalFailures.get()
        );
    }

    /**
     * 获取详细的会话状态信息
     */
    public Map<String, Object> getSessionStats() {
        Map<String, Object> stats = new LinkedHashMap<>();

        int created = 0, active = 0, idle = 0, closing = 0, closed = 0;
        int totalRefCount = 0;

        for (WindowSession session : activeSessions.values()) {
            switch (session.getState()) {
                case CREATED:
                    created++;
                    break;
                case ACTIVE:
                    active++;
                    break;
                case IDLE:
                    idle++;
                    break;
                case CLOSING:
                    closing++;
                    break;
                case CLOSED:
                    closed++;
                    break;
            }
            totalRefCount += session.getReferenceCount();
        }

        stats.put("sessionsCreated", created);
        stats.put("sessionsActive", active);
        stats.put("sessionsIdle", idle);
        stats.put("sessionsClosing", closing);
        stats.put("sessionsClosed", closed);
        stats.put("totalReferenceCount", totalRefCount);
        stats.put("zombieSessionsDetected", totalFailures.get());

        return stats;
    }

    /**
     * 获取详细统计信息
     */
    public Map<String, Object> getDetailedStats() {
        Map<String, Object> stats = new LinkedHashMap<>();
        stats.put("running", running);
        stats.put("waitingCommands", waitingWindows.size());
        stats.put("activeSessions", activeSessions.size());
        stats.put("availableScreenPositions", availableScreenPositions.size());
        stats.put("totalSubmitted", totalSubmitted.get());
        stats.put("totalCompleted", totalCompleted.get());
        stats.put("totalFailures", totalFailures.get());
        stats.put("schedulerThreadAlive", schedulerThread != null && schedulerThread.isAlive());
        stats.put("sessionMonitorThreadAlive", sessionMonitorThread != null && sessionMonitorThread.isAlive());
        stats.put("taskExecutorShutdown", taskExecutor.isShutdown());

        return stats;
    }

    /**
     * 优雅关闭
     */
    public void shutdown() {
        System.out.println("[WindowPool] Shutting down...");

        running = false;

        // 停止调度器和监控器
        if (schedulerThread != null) {
            schedulerThread.interrupt();
        }
        if (sessionMonitorThread != null) {
            sessionMonitorThread.interrupt();
        }

        // 首先清理所有等待的命令
        poolLock.lock();
        try {
            waitingWindows.clear();
            System.out.println("[WindowPool] Cleared " + waitingWindows.size() + " waiting commands");
        } finally {
            poolLock.unlock();
        }

        // 强制清理所有活跃会话
        Iterator<Map.Entry<String, WindowSession>> it = activeSessions.entrySet().iterator();
        int forceCleaned = 0;
        while (it.hasNext()) {
            Map.Entry<String, WindowSession> entry = it.next();
            WindowSession session = entry.getValue();
            System.out.printf("[WindowPool] Force closing session during shutdown: %s, refCount: %d%n",
                    entry.getKey(), session.getReferenceCount());
            session.forceClose();
            it.remove();
            forceCleaned++;
        }
        System.out.printf("[WindowPool] Force closed %d sessions during shutdown%n", forceCleaned);

        // 关闭任务执行器
        taskExecutor.shutdown();
        try {
            if (!taskExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                System.out.println("[WindowPool] Forcing task executor shutdown");
                taskExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            taskExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }

        availableScreenPositions.clear();
        System.out.println("[WindowPool] Shutdown completed");
    }

    /**
     * 紧急关闭（立即终止）
     */
    public void shutdownNow() {
        System.out.println("[WindowPool] Emergency shutdown initiated");

        running = false;

        // 立即终止所有线程
        if (schedulerThread != null) {
            schedulerThread.interrupt();
        }
        if (sessionMonitorThread != null) {
            sessionMonitorThread.interrupt();
        }

        taskExecutor.shutdownNow();

        // 强制清理资源
        activeSessions.values().forEach(session -> {
            try {
                session.forceClose();
            } catch (Exception e) {
                System.err.println("[WindowPool] Error during emergency session cleanup: " + e.getMessage());
            }
        });

        activeSessions.clear();
        waitingWindows.clear();
        availableScreenPositions.clear();

        System.out.println("[WindowPool] Emergency shutdown completed");
    }

    // ==================== 内部类 ====================

    /**
     * 等待中的命令封装
     */
    private static class CommandWaitingWindow {
        final GameWindow window;
        final ICommand command;
        final long submitTime;

        CommandWaitingWindow(GameWindow window, ICommand command) {
            this.window = window;
            this.command = command;
            this.submitTime = System.currentTimeMillis();
        }

        long getSubmitTime() {
            return submitTime;
        }
    }
}